#pragma once
#include <vcclr.h>

using namespace System;
using namespace System::Reflection;
using namespace System::Runtime::InteropServices;
using namespace System::Collections;



void* operator new(size_t	sizet, IDMMemoryAllocator& galloc);
void operator delete(void* pv, IDMMemoryAllocator& galloc);

///////////////////////////////////////////////////////////////////////
// Region PMML Parsing --
//	contains classes used in parsing PMML
///////////////////////////////////////////////////////////////////////

// Generic SAX Content Handler. It implements all the ISAXContentHandler
// methods and returns S_OK 
// Most of thes emthods are not used, because
//	- everything is in the default namespace, hence:
//			startPrefixMapping, endPrefixMapping are not used
//	- this is parsing a document fragment, therefore:
//			startDocument, endDocument are not used
//	- PMML does not contain processing instructions , therefore:
//			processingInstruction, skippedEntity are not used
//	- all the PMML content for this algorithm is in element attributes, not in element text, therefore
//			ignorableWhitespace, characters are not used
//	- error handling is minimal, without displaying XML document location of the error, therefore
//			putDocumentLocator is not used
// Result:
//			The only functions that really need implementation are startElement and endElement
//	To enhance the functionality, in your derived class (PWLinRegPMMLHandler), you should, if necessary:
//		- add better error handling by using the ISAXLocator from putDocumentLocator
//		- treat the element content or raise errors if it is not expected, inside characters() and ignorableWhitespace()
//		- handle namespaces or raise errors in prefixMappings

class PMMLSAXContentHandler : public ISAXContentHandler
{
protected:
	int								m_cRefCount;
	IDMContextServices*				m_wpContext;
	gcroot<System::Object^>			m_algo;
	int								m_depth;

	
	bool							ShouldServerParseStatistics();
	System::Xml::XmlWriter^			Writer();			
	IDMModelServices*				ModelServices();
	void							SwitchToServerParsing();


public:	
	PMMLSAXContentHandler(IDMContextServices*	in_pContext, System::Object^	algo)
	{
		m_cRefCount		=	0;
		m_wpContext		=	in_pContext;
		m_algo			=	algo;
		m_depth			=	0;
	}

	static HRESULT	CreateSAXHandler( IDMContextServices*	in_pContext, System::Object^ algo, PMMLSAXContentHandler** out_ppSAX )
	{
		USES_ERROR_HANDLING;

		CComPtr<IDMMemoryAllocator> spAlloc;	
		RETURN_ON_FAILURE( in_pContext->GetGeneralAlloc(&spAlloc) );

		*out_ppSAX	= new (*spAlloc)PMMLSAXContentHandler( in_pContext , algo);
		return S_OK;
	}

	virtual ~PMMLSAXContentHandler()
	{
	}

	inline void SetInitialDepth( int nDepth )
	{
		m_depth = nDepth;
	}
	

public:
	// IUnknown implementation
	virtual HRESULT STDMETHODCALLTYPE QueryInterface( 
		REFIID riid,
		void __RPC_FAR *__RPC_FAR *ppvObject)
	{
		if( !ppvObject )
			return E_INVALIDARG;
		if( IsEqualIID( riid, __uuidof(IUnknown)  ) )
		{
			*ppvObject	=	(IUnknown*)this;
			AddRef();
			return S_OK;
		}
		else if( IsEqualIID( riid, __uuidof(ISAXContentHandler)  ) )
		{
			*ppvObject	=	(ISAXContentHandler*)this;
			AddRef();
			return S_OK;
		}
		else
			return E_NOINTERFACE;
	}

	virtual ULONG STDMETHODCALLTYPE AddRef(void)
	{
		return ++m_cRefCount;
	}


	virtual ULONG STDMETHODCALLTYPE Release(void)
	{
		if( --m_cRefCount == 0 )
		{
			if( m_wpContext != NULL )
			{
				this->~PMMLSAXContentHandler();
				CComPtr<IDMMemoryAllocator> spAlloc;
				if( SUCCEEDED( m_wpContext->GetGeneralAlloc( &spAlloc ) ) )
				{
					spAlloc->Free((byte*)this);
				}
			}

		}
		return m_cRefCount;
	}

	// ISAXContentHandler implementation
	virtual HRESULT STDMETHODCALLTYPE putDocumentLocator( 
		/* [in] */ ISAXLocator *pLocator){return S_OK;}
    
	virtual HRESULT STDMETHODCALLTYPE startDocument( void){return S_OK;}
    
	virtual HRESULT STDMETHODCALLTYPE endDocument( void){return S_OK;}
    
	virtual HRESULT STDMETHODCALLTYPE startPrefixMapping( 
		/* [in] */ const wchar_t *pwchPrefix,
		/* [in] */ int cchPrefix,
		/* [in] */ const wchar_t *pwchUri,
		/* [in] */ int cchUri){return S_OK;}
    
	virtual HRESULT STDMETHODCALLTYPE endPrefixMapping( 
		/* [in] */ const wchar_t *pwchPrefix,
		/* [in] */ int cchPrefix){return S_OK;}
    
	virtual HRESULT STDMETHODCALLTYPE startElement( 
		/* [in] */ const wchar_t *pwchNamespaceUri,
		/* [in] */ int cchNamespaceUri,
		/* [in] */ const wchar_t *pwchLocalName,
		/* [in] */ int cchLocalName,
		/* [in] */ const wchar_t *pwchQName,
		/* [in] */ int cchQName,
		/* [in] */ ISAXAttributes *pAttributes);
    
	virtual HRESULT STDMETHODCALLTYPE endElement( 
		/* [in] */ const wchar_t *pwchNamespaceUri,
		/* [in] */ int cchNamespaceUri,
		/* [in] */ const wchar_t *pwchLocalName,
		/* [in] */ int cchLocalName,
		/* [in] */ const wchar_t *pwchQName,
		/* [in] */ int cchQName);
    
	virtual HRESULT STDMETHODCALLTYPE characters( 
		/* [in] */ const wchar_t *pwchChars,
		/* [in] */ int cchChars);
    
	virtual HRESULT STDMETHODCALLTYPE ignorableWhitespace( 
		/* [in] */ const wchar_t *pwchChars,
		/* [in] */ int cchChars);
    
	virtual HRESULT STDMETHODCALLTYPE processingInstruction( 
		/* [in] */ const wchar_t *pwchTarget,
		/* [in] */ int cchTarget,
		/* [in] */ const wchar_t *pwchData,
		/* [in] */ int cchData){return S_OK;}
    
	virtual HRESULT STDMETHODCALLTYPE skippedEntity( 
		/* [in] */ const wchar_t *pwchName,
		/* [in] */ int cchName) {return S_OK;}

};

namespace Microsoft
{
namespace SqlServer
{
namespace DataMining
{
namespace PluginAlgorithms
{


	ref struct PMMLElement
	{
		String^	name;
		String^ qname;
		String^ ns;
		String^ content;
	};

	ref struct PMMLAttribute
	{
		String^	name;
		String^ qname;
		String^ ns;
		String^ content;
	};


	[System::Diagnostics::CodeAnalysis::SuppressMessage("Microsoft.Naming", "CA1705:LongAcronymsShouldBePascalCased")]
	public ref class PMMLWriter : public System::Xml::XmlWriter
	{
	internal:
		int								currLevel;
		System::Collections::Stack^		stackElements;
		System::Collections::ArrayList^	arTopAttributes;
		System::Xml::WriteState			writeState;


		void							CheckState();
	internal:
		[System::Diagnostics::CodeAnalysis::SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
		PMMLWriter	(ISAXContentHandler* in_pSAXHandler, IMXAttributes* in_pMXAttributes);
		ISAXContentHandler*	m_wpContentHandler;
		IMXAttributes*		m_wpMXAttributes;


		void MoveToContent();
		
	protected:
		void EndTopElement();
		

	public:
		// ISAX Lexicalhandler for CDATA and comments
		// 
		virtual property System::Xml::WriteState WriteState {
			System::Xml::WriteState get () override
			{
				return writeState;
			}
		}
		virtual void WriteStartDocument () override;
		virtual void WriteStartDocument (bool standalone) override;
		virtual void WriteEndDocument () override;

		virtual void WriteDocType (
			String^ name, 
			String^ pubid, 
			String^ sysid, 
			String^ subset
		)override;

		virtual void Close () override;
		virtual void Flush () override;
		virtual String^ LookupPrefix (String^ ns) override;

		virtual void WriteStartElement (String^ prefix, String^ localName, String^ ns) override;

		virtual void WriteEndElement () override;
		virtual void WriteFullEndElement () override;

		virtual void WriteStartAttribute (String^ prefix, String^ localName, String^ ns) override;
		virtual void WriteEndAttribute () override;

		virtual void WriteCData (String^ text) override;
		virtual void WriteComment (String^ text) override;

		
		virtual void WriteCharEntity (wchar_t ch) override;
		virtual void WriteWhitespace (String^ ws) override;

		virtual void WriteString (String^ text) override;
		virtual void WriteChars (array<wchar_t>^ buffer, int index, int count) override;
		virtual void WriteRaw (String^ data) override;
		virtual void WriteRaw (array<wchar_t>^ buffer, int index, int count) override;
		virtual void WriteBase64 (array<unsigned char>^ buffer, int index, int count) override;

		virtual void WriteProcessingInstruction (String^ name, String^ text) override;
		virtual void WriteSurrogateCharEntity (wchar_t lowChar, wchar_t highChar) override;
		virtual void WriteEntityRef (String^ name) override;

	};
}
}
}
}
